/*
 * Messaging.java
 * Created on Apr 12, 2005 6:51:35 PM
 */
package edu.mobbuzz.messaging;


import java.io.*;
import java.util.*;

import com.alsutton.jabber.JabberDataBlock;
import com.alsutton.jabber.meConnector;
import com.alsutton.jabber.JabberStream;
import com.alsutton.jabber.JabberListener;
import com.alsutton.jabber.block.Login;
import com.alsutton.jabber.block.Message;
import com.alsutton.jabber.block.Presence;
import com.alsutton.jabber.block.Register;
import com.sun.lwuit.Command;
import com.sun.lwuit.Dialog;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import edu.mobbuzz.bean.RSSChannel;
import edu.mobbuzz.facade.MessageFacade;
import edu.mobbuzz.facade.RSSChannelFacade;
import edu.mobbuzz.page.authorization.LoginPage;
import edu.mobbuzz.page.authorization.RegisterForm;
import edu.mobbuzz.page.menu.Menu;
import edu.mobbuzz.page.menu.inbox.InboxPage;
import edu.mobbuzz.util.string.ErrorTool;


public class Messaging extends Menu implements JabberListener {

    // State constant
    public final int NO_STATE 					= -1;
    public final int RESOURCE_BIND             = 0;
    public final int SESSION 					= 1;		
    public final int ONLINE 					= 2;		

    public final int NO_NOTIFICATION    		= 0;
    public final int NOTIFICATION               = 1;

    private String username;			
    private String password;			
    private String domain;				

    public static int GMT_TIMEZONE = 7;// = XMS.GMT_TIMEZONE;
    
    private static JabberStream stream;
    private int state;
    private int mode;
    private int alert;
    public Time time;
    private Thread timeThread;
    
    private MessageFacade messageFacade;
    private RSSChannelFacade rssChannelFacade;
    
    public MessageFacade getMessageFacade() {
        if(messageFacade==null){
            messageFacade = new MessageFacade();
        }
        return messageFacade;
    }

    public RSSChannelFacade getRssChannelFacade() {
        if(rssChannelFacade==null){
            rssChannelFacade = new RSSChannelFacade();
        }
        return rssChannelFacade;
    }

    /**
     * @param midlet
     */
    public Messaging() {
        username = "";
        password = "";
        state = NO_STATE;
        alert = NO_NOTIFICATION;
        time = new Time();
    }

    
    /**
     * @return	True if user is online, otherwise false
     */
    public boolean isOnline() {
        return (getState() >= SESSION);
    }

    /**
     * Connect to Jabber server with port 5222 and continue with user authentication
     */
    public void connect(String hostname, String username, String domain, String password, int mode, ActionListener actionListener, Command exitCmd) throws Exception {
        boolean success = true;
        this.setUsername(username);
        this.setDomain(domain);
        this.setPassword(password);
        setActionlistener(actionListener);
        setExitCmd(exitCmd);
        setMode(mode);
        
        if ((hostname != null) && (username != null) && (domain != null) &&
             (!hostname.equals("")) && (!domain.equals("")) && (!username.equals(""))) {
            
            if (getState() == NO_STATE) {
                try{
                    stream = new JabberStream(new meConnector(hostname, 5222, domain));
                    stream.setJabberListener(this);
                } catch (Exception e) {
                    e.printStackTrace();
                   success = false;
                   Dialog.show("Error", ErrorTool.getCode(500), Dialog.TYPE_ERROR, null, "Ok", null);
                   if(mode==0)
                       backToRegisterForm();
                   else if(mode==1)
                       backToLoginPage();
                }
                if(success){
                    if(mode==0)
                        registrationRequest();
                    else
                        authenticationRequest();
                    }
                }
                
        } else {
            throw(new Exception("EMPTY_FIELD"));
        }

    }

    public void backToRegisterForm(){
        RegisterForm registerForm = new RegisterForm();
        registerForm.setExitCmd(getExitCmd());
        registerForm.setActionlistener(getActionlistener());
        registerForm.showPage();
    }

    public void backToLoginPage(){
        LoginPage loginPage = new LoginPage();
        loginPage.setExitCmd(getExitCmd());
        loginPage.setActionlistener(getActionlistener());
        loginPage.showPage();
    }

    public void backToInboxPage(){
        InboxPage inboxPage = new InboxPage();
        inboxPage.setExitCmd(getExitCmd());
        inboxPage.setActionlistener(getActionlistener());
        inboxPage.showPage();
    }
   

    /**
     * Disconnect from server and close socket
     */
    public void disconnect() {
        if (timeThread != null) {
            if (timeThread.isAlive()) {
                time.stop();
            }
        }
        if (isOnline())
            stream.close();

        setState(NO_STATE);
    }

    /* (non-Javadoc)
     * @see com.alsutton.jabber.JabberListener#beginConversation()
     */
    public void beginConversation() {
        
    }

    public void registrationRequest() {
        try {
        Register register = new Register(getUsername(), getPassword());
        stream.send(register);
        } catch (IOException ex) {
            System.out.println ("No connection available");
            setState(NO_STATE);
        }
        setState(RESOURCE_BIND);
    }

    public void authenticationRequest() {
        Login login = new Login(getUsername(), getPassword(), "mobile");
        try {
            stream.send(login);
        } catch (IOException e) {
            System.out.println ("No connection available");
            setState(NO_STATE);
        }
        setState(SESSION);
    }

    
    /* (non-Javadoc)
     * @see com.alsutton.jabber.JabberListener#blockArrived(com.alsutton.jabber.JabberDataBlock)
     */
    public void blockArrived(JabberDataBlock data) {        
        JabberDataBlock child;
        String tagName = data.getTagName();
        System.out.println("blockArrived......");
        
        if (tagName.equals("iq")) {	
           
            String type = data.getAttribute("type");
            String temp ="";
            String errorCode = "";

            if (getState() == RESOURCE_BIND) {
                System.out.println("RESOURCE_BIND");
                if (type.equals("result")) {
                    authenticationRequest();
                    setState(SESSION);
                } else if (type.equals("error")) {
                    
                    Enumeration enumeration = data.getChildBlocks().elements();
                    if (enumeration.hasMoreElements()) {
                        child = (JabberDataBlock) enumeration.nextElement();
                        temp = child.getTagName();
                        if (temp.equals("error")) {
                            errorCode = child.getAttribute("code");
                            Dialog.show("Error", ErrorTool.getCode(Integer.parseInt(errorCode)), Dialog.TYPE_ERROR, null, "Ok", null);
                            if(getMode()==0)
                               backToRegisterForm();
                            else if(getMode()==1)
                               backToLoginPage();
                        }
                    }
                    
                	setState(NO_STATE);
                    stream.close();
                    
                }
            } else if (getState() == SESSION) {
                System.out.println("SESSION");
                if (type.equals("result")) {
                	sendPresence();
                    setState(ONLINE);
					
                } else if (type.equals("error")) {   				
                    Enumeration enumeration = data.getChildBlocks().elements();
                    if (enumeration.hasMoreElements()) {
                        child = (JabberDataBlock) enumeration.nextElement();
                        temp = child.getTagName();
                        if (temp.equals("error")) {
                            errorCode = child.getAttribute("code");
                            Dialog.show("Error", ErrorTool.getCode(Integer.parseInt(errorCode)), Dialog.TYPE_ERROR, null, "Ok", null);
                            if(getMode()==0)
                               backToRegisterForm();
                            else if(getMode()==1)
                               backToLoginPage();
                        }
                    }
                    setState(NO_STATE);
                    stream.close();
                    
                }
            } else if (getState() == ONLINE) {		// Iq of time
                
            }
        } else if (tagName.equals("message")) {
            System.out.println("stream is coming...");
           

            Enumeration enumeration = data.getChildBlocks().elements();
            JID from = JID.parseJIDString(data.getAttribute("from"));
            JID to   = JID.parseJIDString(data.getAttribute("to"));

            String temp = data.getAttribute("type");

            if (temp != null) {
                if (temp.equals("error")) {
                    String errorCode = "";
                    if (enumeration.hasMoreElements()) {
                        child = (JabberDataBlock) enumeration.nextElement();
                        temp = child.getTagName();
                        if (temp.equals("error")) {
                            errorCode = child.getAttribute("code");
                        }
                    }
                    if (errorCode.equals("404")) {
                       
                    }
                }  else {
                    processMessage(enumeration, from, to);
                }
            } else {
                processMessage(enumeration, from, to);
            }

        } else if (tagName.equals("stream:error")) {
            setState(NO_STATE);
            stream.closeStream();            
           
        } else if (tagName.equals("xms:server_close_stream")) {            
            setState(NO_STATE);
            stream.closeStream();
        }

    }

    private void sendPresence(){
		Presence presence = new Presence();
        try {
            stream.send(presence);
        } catch (IOException e) {
            System.out.println ("No connection available");
            setState(NO_STATE);
        }
	}
    private void processMessage(Enumeration enumeration, JID from, JID to) {
        JabberDataBlock child, body;
		String temp;
        System.out.println("processMessage...");
		while (enumeration.hasMoreElements()) {
			child = (JabberDataBlock) enumeration.nextElement();
            temp = child.getTagName();
            if (temp.equals("body")) {
            	if(child.getChildBlocks()!=null){
            		Enumeration bodyEnum = child.getChildBlocks().elements();
                    if(bodyEnum.hasMoreElements()){
                        body = (JabberDataBlock) bodyEnum.nextElement();
                        if(body.getTagName().equals("news")){
                            processNews(body, from, to);
                        }else if(body.getTagName().equals("result")){
                            processResult(body, from, to);
                        }
                    }
            	}else{
                    edu.mobbuzz.bean.Message msg = new edu.mobbuzz.bean.Message();
                    msg.setSource("");
                    msg.setLink("");
                    msg.setTitle("");
                    msg.setDescription(child.getText());
                    msg.setPubdate("");
                    msg.setDate("");
                    msg.setFrom(from.username+"@"+from.domain);
                    msg.setType(1);
                    msg.setRead(false);
                    getMessageFacade().addMessage(msg);
               }
            }
		}
    }

    private void processResult(JabberDataBlock body, JID from, JID to) {
        JabberDataBlock result;
        String id="", url="", title="";
        String type= body.getAttribute("type");

        System.out.println(type);
        Enumeration newsEnum = body.getChildBlocks().elements();
        while(newsEnum.hasMoreElements()){
            result = (JabberDataBlock) newsEnum.nextElement();
            if (result.getTagName().equals("url")) {
                url = result.getText();
                System.out.println(url);
            }else if (result.getTagName().equals("title")) {
                title = result.getText();
                System.out.println(title);
            }
        }

        if(type.equals("reg")){
            RSSChannel reg = new RSSChannel();
            reg.setTitle(title);
            reg.setSource(url);
            reg.setLabel("");
            getRssChannelFacade().addRSSChannel(reg);
            
        }else if(type.equals("unreg")){
            Vector deletedRSS = getRssChannelFacade().getIndexBySource(url);
            for(int i=0;i<deletedRSS.size();i++){
                int deletedRSSChannel = Integer.parseInt(String.valueOf((Integer)deletedRSS.elementAt(i)));
                getRssChannelFacade().deleteRSSChannel(deletedRSSChannel);
            }
        }

        
    }
    private void processNews(JabberDataBlock body, JID from, JID to) {
		JabberDataBlock news;
        String title="", description="", link="", date="", url="";
       
        Enumeration newsEnum = body.getChildBlocks().elements();
        while(newsEnum.hasMoreElements()){
            news = (JabberDataBlock) newsEnum.nextElement();
            if (news.getTagName().equals("url")) {
                url = news.getText();
            }else if (news.getTagName().equals("link")) {
                link = news.getText();
            }else if (news.getTagName().equals("title")) {
                title = news.getText();
            }else if (news.getTagName().equals("description")) {
                description = news.getText();
            }else if (news.getTagName().equals("date")) {
                date = news.getText();
            }
            
            
        }
        //if((!url.equals(""))&&(!link.equals(""))&&(!title.equals(""))&&(!description.equals(""))&&(!date.equals(""))){
            edu.mobbuzz.bean.Message msg = new edu.mobbuzz.bean.Message();
            msg.setSource(url);
            msg.setLink(link);
            msg.setTitle(title);
            msg.setDescription(description);
            msg.setPubdate(date);
            msg.setDate(date);
            msg.setFrom(from.username+"@"+from.domain);
            msg.setType(1);
            msg.setRead(false);
            getMessageFacade().addMessage(msg);
        //}

        Command noCommand = new Command("Skip");
        Command yesCommand = new Command("Go To Inbox"){
            public void actionPerformed(ActionEvent evt) {
                backToInboxPage();
            }
        };
        Dialog.show("Information", "You Have New Messages In Your Inbox", new Command[] {noCommand, yesCommand}, Dialog.TYPE_INFO, null, 10000);
        

    		
    }
    /* (non-Javadoc)
     * @see com.alsutton.jabber.JabberListener#connectionTerminated(java.lang.Exception)
     */
    public void connectionTerminated(Exception e) {
        setState(NO_STATE);
        if (e != null) {		// Connection not normally terminated
			/*parent.ackMessage = "Connection Terminated";
			parent.getPage (Constant.error);*/
        }
    }


    /**
     * @param challange		Base64 decoded challange string sent by server
     * @return				Hashtable containing attribute and value of challange
     */
    private static Hashtable parseChallange(String challange) {
        Hashtable result = new Hashtable();
        if ((challange != null) && (!challange.equals(""))) {
            int start = 0;
            int pos = 0;
            int length = challange.length();
            String value = "";
            String attribute = "";
            char startChar;
            while ((pos = challange.indexOf("=", start)) >= 0) {
                attribute = challange.substring(start, pos);
                start = pos + 1;
                pos = challange.indexOf(",", start);
                if (pos == -1) {
                    pos = length;
                }
                startChar = challange.charAt(start);
                if (startChar == '"') {
                    value = challange.substring(start + 1, pos - 1);
                } else {
                    value = challange.substring(start, pos);
                }
                if (startChar < length)
                    start = pos + 1;
                result.put(attribute, value);
            }
        }
        return result;
    }


   

    /**
     * Send message to other client
     * @param to		Recipient JID
     * @param message	Message content
     * @return			True if successful, false otherwise
     */
    public boolean sendMessage(String to, String message) {        
        try {
            Message _message = new Message( to, message );
            stream.send(_message);
            return true;
        } catch (IOException ex) {
            ex.printStackTrace();
            return false;
        }

        
    }

    /**
     * Change occurances of &amplt; , &ampgt; , &ampamp; , &ampapos; , &ampquot
     * in input string with < , > , & , ' , "
     * @param input		String to be decoded
     * @return			Decoded string
     */
    private String decodeEscapedCharacters(String input) {
        StringBuffer output = new StringBuffer();
        char[] arrayInput = input.toCharArray();
        int length = arrayInput.length;
        int i = 0;
        while (i < length) {
            if (arrayInput[i] == '&') {
                i++;
                if (arrayInput[i] == 'l') {			// &lt;
                    output.append('<');
                } else if (arrayInput[i] == 'g') { 	// &gt;
                    output.append('>');
                } else if (arrayInput[i] == 'q') {	// &quot;
                    output.append('"');
                } else if (arrayInput[i] == 'a') {
                    i++;
                    if (arrayInput[i] == 'm') {		// &amp;
                        output.append('&');
                    } else if (arrayInput[i] == 'p') {	// &apos;
                        output.append('\'');
                    }
                }
                while (arrayInput[++i] != ';');
            } else {
                output.append(arrayInput[i]);
            }
            i++;
        }
        return output.toString();
    }

    /**
     * Change occurances of < , > , & , ' , " in input string with &amplt; , &ampgt; ,
     * &ampamp; , &ampapos; , &ampquot;
     * @param input		String to be encoded
     * @return			Encoded string
     */
    public static String encodeEscapedCharacters(String input) {
        StringBuffer output = new StringBuffer();
        char []arrayInput = input.toCharArray();
        int length = arrayInput.length;
        int i = 0;

        while (i < length) {
            if (arrayInput[i] == '<') {
                output.append("&lt;");
            } else if (arrayInput[i] == '>') {
                output.append("&gt;");
            } else if (arrayInput[i] == '&') {
                output.append("&amp;");
            } else if (arrayInput[i] == '\'') {
                output.append("&apos;");
            } else if (arrayInput[i] == '"') {
                output.append("&quot;");
            } else {
                output.append(arrayInput[i]);
            }
            i++;
        }
        return output.toString();
    }

    public String getCurrentTime() {
        return time.getCurrentTime();
    }

    /**
     * @return the state
     */
    public int getState() {
        return state;
    }

    /**
     * @param state the state to set
     */
    public void setState(int state) {
        this.state = state;
    }

    /**
     * @return the alert
     */
    public int getAlert() {
        return alert;
    }

    /**
     * @param alert the alert to set
     */
    public void setAlert(int alert) {
        this.alert = alert;
    }

    
    public String getMenuTitle() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void showPage() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * @return the mode
     */
    public int getMode() {
        return mode;
    }

    /**
     * @param mode the mode to set
     */
    public void setMode(int mode) {
        this.mode = mode;
    }

    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @return the domain
     */
    public String getDomain() {
        return domain;
    }

    /**
     * @param domain the domain to set
     */
    public void setDomain(String domain) {
        this.domain = domain;
    }
}